package pl.register.android.activities.correlation.logic;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import com.google.inject.Singleton;
import pl.register.android.activities.correlation.ui.CorrelationView;
import pl.register.android.activities.profile.StudentProfileActivity;
import pl.register.android.database.exception.CanNotAddLessonProgramException;
import pl.register.android.database.exception.NotFoundCourseException;
import pl.register.android.classes.Classes;
import pl.register.android.course.Course;
import pl.register.android.database.DatabaseAdapter;
import pl.register.android.database.dao.*;
import pl.register.android.database.exception.NotFoundNextLessonProgramException;
import pl.register.android.group.StudentsGroup;
import pl.register.android.homework.Homework;
import pl.register.android.lesson.Lesson;
import pl.register.android.lesson.LessonProgram;
import pl.register.android.lesson.TagLesson;
import pl.register.android.preferences.ResotorePreferences;
import pl.register.android.program.Program;
import pl.register.android.student.Student;
import pl.register.android.util.StringUtils;
import pl.register.android.year.Year;
import pl.register.android.year.YearType;

import java.util.List;

/**
 * @author Mateusz Strzelecki
 * @since 2013-04-19
 */
@Singleton
public class CorrelationStudentsPresenter {

    private DatabaseAdapter databaseAdapter;

    private CorrelationView correlationView;

    private CourseDao courseDao;

    private StudentGroupDao groupDao;

    private StudentsDao studentsDao;

    private ProgramDao programDao;

    private StudentLessonDao lessonDao;


    private Course displayCourse;

    private Correlation displayCorrelation;

    private TagLesson selectedTag;

    public CorrelationStudentsPresenter(DatabaseAdapter databaseAdapter, CorrelationView correlationView) {
        this.databaseAdapter = databaseAdapter;
        this.courseDao = databaseAdapter.getCourseDao();
        this.groupDao = databaseAdapter.getStudentGroupDao();
        this.programDao = databaseAdapter.getProgramDao();
        this.studentsDao = databaseAdapter.getStudentDao();
        this.lessonDao = databaseAdapter.getStudentLessonDao();
        this.correlationView = correlationView;
    }

    public void initWith(Course course) {
        this.displayCourse = course;
    }

    public void populateViews(TagLesson tagLesson, List<Correlation> correlations, YearType yearType) {
        correlationView.populateCorrelations(correlations);
        displayCorrelation = correlationView.settleCorrelationBy(yearType);
        selectedTag = tagLesson;
        if (displayCourse != null) {
            correlationView.populateCourse("" + displayCourse.getStartYear(), "" + displayCourse.getEndYear());
            refreshTable(tagLesson);
        }
    }

    public void refreshTable(TagLesson tagLesson) {
        if (displayCourse != null) {
            correlationView.refreshTitle(tagLesson, displayCourse);
        }

        if (displayCorrelation != null) {
            displayCorrelation.setProgram(tagLesson);
            settleStudentsLessonsIn(displayCorrelation);
            correlationView.populateTable(displayCorrelation);
        }
    }

    private void settleStudentsLessonsIn(Correlation correlation) {
        Program program = correlation.getProgram();
        for (StudentsGroup group : correlation.getGroups()) {
            List<Student> students = group.getStudents();
            for (Student student : students) {
                List<Lesson> lessons = lessonDao.findLessonsFor(student, program);
                student.setLessons(lessons);
            }
        }
    }

    public void rebuildForNextCourse(Context context) throws NotFoundCourseException {
        Course nextCourse = new Course(displayCourse.getStartYear() + 1, displayCourse.getEndYear() + 1);
        courseDao.findCourseFor(nextCourse.getStartYear(), nextCourse.getEndYear());
        displayCorrelation = null;
        new AsyncCorrelationLoader(context, correlationView, this, nextCourse).execute();
    }

    public void rebuildForPreviousCourse(Context context) throws NotFoundCourseException {
        Course previousCourse = new Course(displayCourse.getStartYear() - 1, displayCourse.getEndYear() - 1);
        courseDao.findCourseFor(previousCourse.getStartYear(), previousCourse.getEndYear());
        displayCorrelation = null;
        new AsyncCorrelationLoader(context, correlationView, this, previousCourse).execute();
    }

    public void changeCorrelation(Context context, Correlation correlation) {
        if (!correlation.equals(displayCorrelation)) {
            this.displayCorrelation = correlation;
            refreshTable(selectedTag);
            ResotorePreferences.saveCorrelationYearType(context, correlation.getYear().getType());
        }
    }

    public void changeTagLesson(Context context, TagLesson tagLesson) {
        if (!tagLesson.equals(selectedTag)) {
            this.selectedTag = tagLesson;
            refreshTable(selectedTag);
            ResotorePreferences.saveTag(context, tagLesson);
        }
    }

    public List<Student> getStudentsWithoutGroup() {
        Year studentYear = displayCorrelation.getYear();
        return studentsDao.findStudentsWithoutGroupBy(studentYear, displayCourse);
    }

    public void addStudentToGroup(Student student, StudentsGroup group) {
        groupDao.addStudentTo(student, group);
        List<Lesson> lessons = lessonDao.findLessonsFor(student, group.getProgram());
        student.setLessons(lessons);
        displayCorrelation.addStudentTo(student, group);
        correlationView.populateTable(displayCorrelation);
    }

    public void deleteStudentFromGroup(Student student, StudentsGroup group) {
        groupDao.deleteStudentFrom(student, group);
        displayCorrelation.removeStudentFrom(student, group);
        correlationView.populateTable(displayCorrelation);
    }

    public void addNextLessonProgram() throws NotFoundNextLessonProgramException, CanNotAddLessonProgramException {
        Year year = displayCorrelation.getYear();
        List<StudentsGroup> groups = displayCorrelation.getGroups();
        checkCanAddLessonProgramTo(year, selectedTag);

        LessonProgram nextLessonProgram = getNextLessonProgram(groups.get(0), year);
        nextLessonProgram.setTagLesson(selectedTag);
        for (StudentsGroup group : groups) {
            programDao.insertLessonProgramTo(nextLessonProgram, group);
        }
        displayCorrelation.addLessonProgram(nextLessonProgram);
        for (Student student : displayCorrelation.getAllStudents()) {
            Lesson nextLesson = lessonDao.findLessonFor(student, nextLessonProgram);
            student.addLesson(nextLesson);
        }

        correlationView.populateTable(displayCorrelation);
    }

    private LessonProgram getNextLessonProgram(StudentsGroup group, Year year) throws NotFoundNextLessonProgramException {
        Program groupProgram = group.getProgram();
        Program yearProgram = year.getProgram();
        LessonProgram nextLessonProgram = programDao.findNextLessonProgram(groupProgram.getLastLessonProgram(), year);
        if (nextLessonProgram == null) {
            nextLessonProgram = yearProgram.getProgramLessonBy(programDao.countLessonProgramIn(group));
        } else {
            displayCorrelation.removeLessonProgram(nextLessonProgram);
        }

        if (nextLessonProgram == null) {
            throw new NotFoundNextLessonProgramException();
        } else {
            return nextLessonProgram;
        }
    }

    private void checkCanAddLessonProgramTo(Year year, TagLesson tag) throws CanNotAddLessonProgramException {
        YearType yearType = year.getType();
        String msg = StringUtils.build("Niestety dla wybranego roku nie można dodać zajęć do zakładki '", tag.getName(), "'");
        if (yearType.equals(YearType.HOLIDAY_I_YEAR) && !tag.equals(TagLesson.HOLIDAY_I)) {
            throw new CanNotAddLessonProgramException(msg);
        } else if (yearType.equals(YearType.HOLIDAY_II_YEAR) && !tag.equals(TagLesson.HOLIDAY_II)) {
            throw new CanNotAddLessonProgramException(msg);
        } else if ((!yearType.equals(YearType.HOLIDAY_I_YEAR) && !yearType.equals(YearType.HOLIDAY_II_YEAR)) &&
                (tag.equals(TagLesson.HOLIDAY_I) || tag.equals(TagLesson.HOLIDAY_II))) {
            throw new CanNotAddLessonProgramException(msg);
        }
    }

    public void deleteLessonProgram(LessonProgram toRemove) {
        List<StudentsGroup> groups = displayCorrelation.getGroups();
        for (StudentsGroup group : groups) {
            programDao.deleteLessonProgramFrom(toRemove, group);
        }
        displayCorrelation.removeFromDisplayLessonProgram(toRemove);
        for (Student student : displayCorrelation.getAllStudents()) {
            student.removeLastLesson();
        }
        correlationView.populateTable(displayCorrelation);
    }

    public void updateLessonProgram(LessonProgram lessonProgram) {
        for (StudentsGroup group : displayCorrelation.getGroups()) {
            programDao.updateLessonProgramIn(lessonProgram, group);
        }
    }

    public boolean correlationIsSelected() {
        return displayCorrelation != null;
    }

    public void saveClasses(Classes classes) {
        lessonDao.updateStudentClasses(classes);
    }

    public void saveHomework(Homework homework) {
        lessonDao.updateStudentHomework(homework);
    }

    public DatabaseAdapter getDatabaseAdapter() {
        return databaseAdapter;
    }

    public Correlation getDisplayCorrelation() {
        return displayCorrelation;
    }

    public void goToProfile(Activity activity, Student student, Year year) {
        Intent intentProfile = new Intent(activity, StudentProfileActivity.class);
        intentProfile.putExtra(StudentProfileActivity.EXTRA_YEAR_ID, year.getId());
        intentProfile.putExtra(StudentProfileActivity.EXTRA_STUDENT_ID, student);
        intentProfile.putExtra(StudentProfileActivity.EXTRA_COURSE_ID, displayCourse.getId());
        activity.startActivity(intentProfile);
    }

}